package cbs.jdtag;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JPanel;

import cbs.jdtag.DataModel2.Alignment;
import cbs.jdtag.DataModel2.Token;

public class AlignmentAreaPanel2 extends JPanel implements Observer {
	
	private static final long serialVersionUID = -2837236442815655478L;
	private transient final Logger logger = Logger.getLogger(this.getClass().getName());
	private static final BasicStroke stroke = new BasicStroke(2);
	
	public AlignmentAreaPanel2() {
		AppContext.getDM().addObserver(this);
		
		addMouseMotionListener(new MouseMotionAdapter() {
			
			TokenLabel2 last;
			
			@Override
			public void mouseMoved(MouseEvent e) {
				super.mouseMoved(e);
				
				Component c = getComponentAt(e.getPoint());
				if (c instanceof TokenLabel2) {
					
					TokenLabel2 tl = (TokenLabel2) c;
					if (tl == last) {
						return;
					}
					else if (last != null) {
						setHiglighted(last.getToken().alignments, false);	
					}
					
					setHiglighted(tl.getToken().alignments, true);
					last = tl;
					
					repaint();
				}
				else if (last != null) {
					setHiglighted(last.getToken().alignments, false);
					last = null;
				}
			}});
		
		setBackground(Color.WHITE);
		setLayout(null);
	}
    
	@Override
	public void validate() {
		
		displayTokenLabels();
		super.validate();
	}

	public void displayTokenLabels() {
		DataModel2 dm = AppContext.getDM();
		
		logger.fine("Displaying token labels...");
		
		removeAll();
		
		if (dm.isEmpty()) {
			setPreferredSize(new Dimension(1, 1));
			repaint();
			return;
		}
		
    	int x;

    	x = getSize().width / 2 - 100 - TokenLabel2.WIDTH;
    	addLabels(x, 0, false);

		x = getSize().width / 2 + 100;
		addLabels(x, 1, true);
		
		int newHeight = dm.getMaxTokenCount() * TokenLabel2.HEIGHT;
		setPreferredSize(new Dimension(getPreferredSize().width, newHeight));
		
		repaint();
    }
	
	@Override
    public void paintComponent(Graphics g) {
		super.paintComponent(g);

		displayAlignments(g);
    }
	
	public void displayAlignments(Graphics g) {
		DataModel2 dm = AppContext.getDM();
		
		logger.fine("Displaying alignment lines...");
		
		if (dm.getAlignmentIterator() == null) {
			return;
		}
		
		Iterator<Alignment> it = dm.getAlignmentIterator();
		while (it.hasNext()) {
			Alignment a = it.next();
			
			Iterator<Token> srcIt = a.getSrcTokens().iterator();
			while (srcIt.hasNext()) {

				Token srcToken = srcIt.next();
				
				Iterator<Token> tgtIt = a.getTgtTokens().iterator();
				while (tgtIt.hasNext()) {
					
					Token tgtToken = tgtIt.next();
					
					int x1 = srcToken.x + TokenLabel2.WIDTH;
					int y1 = srcToken.y + TokenLabel2.HEIGHT / 2;
					int x2 = tgtToken.x;
					int y2 = tgtToken.y + TokenLabel2.HEIGHT / 2;
					
					logger.log(Level.FINE, "Drawing coordinates \"{0}\", \"{1}\", \"{2}\", \"{3}\"", new Object[]{x1, y1, x2, y2});

					if (srcToken.highlighted && tgtToken.highlighted) {
						g.setColor(Color.BLUE);
					}
					else {
						g.setColor(Color.RED);
					}
					
					((Graphics2D) g).setStroke(stroke);
					g.drawLine(x1, y1, x2, y2);
				}	
			}
		}
	}

	public void update(Observable o, Object arg) {
		displayTokenLabels();
    	getParent().validate();
	}
	
	private void addLabels(int x, int keyIndex, boolean posLeft) {
		
		DataModel2 dm = AppContext.getDM();
		
		if (keyIndex >= dm.getKeyCount()) return;
		
    	Iterator<DataModel2.Token> it = dm.getTokenIterator(dm.getKey(keyIndex));
    	int y = 0;
    	
		while (it.hasNext()) {
			Token t = it.next();
			t.x = x;
			t.y = y;

			TokenLabel2 tl = new TokenLabel2(t, posLeft);
			add(tl);

			y = y + TokenLabel2.HEIGHT;
		}
	}
	
	private void setHiglighted(List<Alignment> alignments, boolean value) {

		Iterator<Alignment> it = alignments.iterator();
		while (it.hasNext()) {
			Alignment a = it.next();
			
			Iterator<Token> tIt;
			
			tIt = a.getSrcTokens().iterator();
			while (tIt.hasNext()) {
				Token t = tIt.next();
				t.highlighted = value;
//				t.tokenLabel.setHighlighted(value);
			}
			
			tIt = a.getTgtTokens().iterator();
			while (tIt.hasNext()) {
				Token t = tIt.next();
				t.highlighted = value;
//				t.tokenLabel.setHighlighted(value);
			}
		}
	}
}
